﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using HadronData;

namespace Hadron.Entities
{
    class GravityDevice
        : Entity
    {
        private static Polygon s_polygonContact, s_polygonVisible;

        private bool m_bAttractor;
        private double m_dTime;
        private Polygon m_polygonContact, m_polygonVisible;

        private Vector2 ComputeFieldAcceleration(Vector2 p_vecPosition)
        {
            Vector2 vecAcceleration = p_vecPosition - Position;
            double dDistance = (double)vecAcceleration.Length();
            vecAcceleration.Normalize();
            vecAcceleration *= (float)(8192.0 / dDistance);
            return m_bAttractor ? -vecAcceleration : vecAcceleration;
        }

        public GravityDevice(EntityMarker p_entityMarker, Environment p_environment, bool p_bAttractor)
            : base(p_entityMarker, p_environment)
        {
            if (s_polygonContact == null)
            {
                s_polygonContact = new Polygon();
                s_polygonVisible = new Polygon();

                float fAngleDelta = MathHelper.TwoPi / 6;
                for (int nIndex = 0; nIndex < 6; nIndex++)
                {
                    Vector2 vecVertex1 = new Vector2(
                        (float) Math.Cos(fAngleDelta * nIndex) * 32.0f,
                        (float) Math.Sin(fAngleDelta * nIndex) * 32.0f);
                    Vector2 vecVertex2 = new Vector2(
                        (float)Math.Cos(fAngleDelta * (nIndex + 1)) * 32.0f,
                        (float)Math.Sin(fAngleDelta * (nIndex + 1)) * 32.0f);

                    Vector2 vecVertex3 = vecVertex1 * 0.5f;
                    Vector2 vecVertex4 = vecVertex2 * 0.5f;

                    s_polygonContact.Edges.Add(new Edge(vecVertex1, vecVertex2));

                    s_polygonVisible.Edges.Add(new Edge(vecVertex1, vecVertex2));
                    s_polygonVisible.Edges.Add(new Edge(vecVertex3, vecVertex4));
                    s_polygonVisible.Edges.Add(new Edge(vecVertex1, vecVertex3));
                }
                s_polygonContact.UpdateBounds();
                s_polygonVisible.UpdateBounds();
            }

            m_polygonContact = new Polygon(s_polygonContact);
            m_polygonContact.Transform(m_trnPlacement);

            m_polygonVisible = new Polygon(s_polygonVisible);
            m_polygonVisible.Transform(m_trnPlacement);

            m_bAttractor = p_bAttractor;
            m_nHealth = 100;

            m_circleBounds = s_polygonContact.GetBoundingCircle(Vector2.Zero);
        }

        public override void Update(GameTime p_gameTime)
        {
            m_dTime = p_gameTime.TotalGameTime.TotalSeconds;
            float fDeltaTime = (float) p_gameTime.ElapsedGameTime.TotalSeconds;

            // affect player ship
            PlayerShip playerShip = m_environment.PlayerShip;
            if (playerShip.Status == PlayerShipStatus.Active)
                playerShip.Velocity += ComputeFieldAcceleration(playerShip.Position) * fDeltaTime;

            // affect crates
            foreach (Entity entity in m_environment.Entities)
                if (entity.Type == EntityType.Crate)
                {
                    if (!((Crate) entity).Delivered)
                        entity.Velocity += ComputeFieldAcceleration(
                            entity.Position) * fDeltaTime;
                }

            m_polygonContact.Transform(m_trnPlacement, s_polygonContact);
            m_polygonVisible.Transform(m_trnPlacement, s_polygonVisible);
        }

        public override void Draw(SpriteBatch p_spriteBatch)
        {
            // device
            m_polygonVisible.Draw(p_spriteBatch);

            double dTheta = m_dTime * Math.PI;
            float fIntensity1 = 0.5f + (float)Math.Cos(dTheta) * 0.5f;
            float fIntensity2 = 0.5f + (float)Math.Cos(dTheta + Math.PI * 2.0 / 3.0) * 0.5f;
            float fIntensity3 = 0.5f + (float)Math.Cos(dTheta + Math.PI * 4.0 / 3.0) * 0.5f;

            Color colour1, colour2, colour3;
            if (m_bAttractor)
            {
                colour1 = new Color(fIntensity1, 0.0f, fIntensity1);
                colour2 = new Color(fIntensity2, 0.0f, fIntensity2);
                colour3 = new Color(fIntensity3, 0.0f, fIntensity3);
            }
            else
            {
                colour1 = new Color(0.0f, fIntensity1 * 0.25f, fIntensity1);
                colour2 = new Color(0.0f, fIntensity2 * 0.25f, fIntensity2);
                colour3 = new Color(0.0f, fIntensity3 * 0.25f, fIntensity3);
            }

            // lights
            Vector2 vecOrigin = new Vector2(16.0f, 48.0f);
            p_spriteBatch.Draw(AssetManager.Textures.GravityDeviceGlow, Position, null,
                colour1, 0.0f, vecOrigin, 1.0f, SpriteEffects.None, 0.0f);
            p_spriteBatch.Draw(AssetManager.Textures.GravityDeviceGlow, Position, null,
                colour2, MathHelper.TwoPi / 3.0f, vecOrigin, 1.0f, SpriteEffects.None, 0.0f);
            p_spriteBatch.Draw(AssetManager.Textures.GravityDeviceGlow, Position, null,
                colour3, MathHelper.TwoPi * 2.0f / 3.0f, vecOrigin, 1.0f, SpriteEffects.None, 0.0f);

            // gravity waves
            vecOrigin.X = 64.0f; vecOrigin.Y = 64.0f;
            Color colour;
            for (int nIndex = 0; nIndex < 8; nIndex++)
            {
                float fScale = (float)((m_dTime + nIndex * 0.5) % 4.0);
                if (m_bAttractor) fScale = 4.0f - fScale;
                float fOpacity = 1.0f - fScale * 0.25f;
                if (m_bAttractor)
                    colour = new Color(fOpacity * 0.125f, 0.0f, fOpacity * 0.125f);
                else
                    colour = new Color(0.0f, fOpacity * 0.0625f, fOpacity * 0.125f);
                p_spriteBatch.Draw(AssetManager.Textures.Ring, Position, null, colour, 0.0f,
                    vecOrigin, fScale, SpriteEffects.None, 0.0f);
            }
        }

        public override EntityType Type
        {
            get { return m_bAttractor ? EntityType.Attractor : EntityType.Repulsor; }
        }

        public override bool Destructuble
        {
            get { return false; }
        }

        public override bool Hostile
        {
            get { return true; }
        }

        public override Geometry Geometry
        {
            get { return m_polygonContact; }
        }
    }
}
